﻿using browser4gp.core;
using browser4gp.core.Plugin;
using browser4gp.core.Style;
using System;
using System.Collections.Generic;
using System.ComponentModel.Composition;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading;
using System.Windows;
using System.Windows.Threading;
using wpf4gp.Helpers;
using common4gp;
using documentPlugin.Properties;
using System.ComponentModel;
using System.Net;
using browser4gp.core.Helpers;
using System.Diagnostics;

namespace documentPlugin
{

    /// <summary>
    /// View model
    /// </summary>
    [Export(typeof(IBrowserPlugin))]
    [ExportMetadata(BrowserPluginMetadataProperties.Name, "DocumentPlugin")]
    [ExportMetadata(BrowserPluginMetadataProperties.Description, "Document manager")]
    [ExportMetadata(BrowserPluginMetadataProperties.JavascriptObjectName, "nativeApp")]
    public class DocumentViewModel : BaseBrowserPlugin
    {

        /// <summary>
        /// Costruttore di base
        /// </summary>
        /// <param name="mainStyle">Stile di riferimento</param>
        [ImportingConstructor]
        public DocumentViewModel([Import("MainWindowStyle")] MainWindowStyle mainStyle) 
            : base(mainStyle)
        {
            StatusBarElement = new DocumentStatusBar(this);
            // Faccio partire il thread di controllo allegati
            documentsTimer = new DispatcherTimer();
            documentsTimer.Tick += CheckOpenedDocuments;
            documentsTimer.Interval = TimeSpan.FromSeconds(5);
            documentsTimer.Start();
        }


        /// <summary>
        /// Esegue il codice richiamato da JavaScript
        /// </summary>
        /// <param name="methodName">Nome del metodo richiamato da JavaScript</param>
        /// <param name="args">Argomenti</param>
        /// <returns>Esito dell'operazione</returns>
        public override string RunFromJavascript(string methodName, List<string> args)
        {
            if (methodName.Equals("OpenDocument", StringComparison.InvariantCultureIgnoreCase))
            {
                if (args.Count > 0)
                {
                    string documentURL = args[0];
                    OpenDocument(documentURL);
                }
            }
            return "OK";
        }


        #region Elemento della status bar


        private UIElement _statusBarElement;

        /// <summary>
        /// Elemento da visualizzare nella status bar
        /// </summary>
        public override UIElement StatusBarElement
        {
            get 
            {
                return _statusBarElement;
            }
            protected set
            {
                if (_statusBarElement != value)
                {
                    _statusBarElement = value;
                    RaisePropertyChanged(() => StatusBarElement);
                }
            }
        }

        #endregion


        #region Messaggio relativo ai documenti aperti


        private string _message;
        
        /// <summary>
        /// Messaggio della status bar
        /// </summary>
        public string Message
        {
            get
            {
                if (string.IsNullOrEmpty(_message) &&
                    !OpenedDocuments.IsNullOrEmpty())
                {
                    return string.Format(Resources.OpenedDocuments, OpenedDocuments.Count());
                }
                return _message;
            }
            set
            {
                if (_message != value)
                {
                    _message = value;
                    RaisePropertyChanged(() => Message);
                }
            }
        }


        #endregion


        #region Apertura documenti



        /// <summary>
        /// Apre uno specifico documento
        /// </summary>
        /// <param name="documentURL">Documento da aprire</param>
        private void OpenDocument(string documentURL)
        {
            Message = Resources.OpeningDocument;
            using (BackgroundWorker documentWorker = new BackgroundWorker())
            {
                documentWorker.RunWorkerCompleted += documentWorker_RunWorkerCompleted;
                documentWorker.DoWork += documentWorker_DoWork;
                documentWorker.RunWorkerAsync(documentURL);
            }
        }

        private void documentWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            Application.Current.Dispatcher.Invoke((ThreadStart)delegate
            {
                Message = null;
            });
        }

        private void documentWorker_DoWork(object sender, DoWorkEventArgs e)
        {
            string documentUrl = e.Argument as string;
            Uri attachUri = new Uri(documentUrl, UriKind.RelativeOrAbsolute);
            if (attachUri != null)
            {
                string filePath = string.Empty;
                // Eseguo il download
                using (WebClient client = new WebClient())
                {
                    using (Stream rawStream = client.OpenRead(attachUri))
                    {
                        string fileName = DateTime.UtcNow.Ticks.ToString();
                        // Nome dal content-disposition
                        string contentDisposition = client.ResponseHeaders["content-disposition"];
                        if (!string.IsNullOrEmpty(contentDisposition))
                        {
                            string lookFor = "filename=";
                            int index = contentDisposition.IndexOf(lookFor, StringComparison.CurrentCultureIgnoreCase);
                            if (index >= 0)
                            {
                                fileName = Path.GetFileName(contentDisposition.Substring(index + lookFor.Length));
                            }
                        }
                        // Nome dal path
                        else
                        {
                            string completeUrl = attachUri.ToString();
                            int paramSeparator = completeUrl.IndexOf('?');
                            string urlWithoutParameters = completeUrl;
                            if (paramSeparator > 0)
                            {
                                urlWithoutParameters = completeUrl.Substring(0, paramSeparator);
                            }
                            paramSeparator = urlWithoutParameters.LastIndexOf('/');
                            string urlName = urlWithoutParameters;
                            if (paramSeparator > 0)
                            {
                                urlName = urlWithoutParameters.Substring(paramSeparator +1);
                            }
                            try
                            {
                                string fName = Path.GetFileName(urlName);
                                if (!string.IsNullOrEmpty(Path.GetExtension(fName)))
                                {
                                    fileName = fName;
                                }
                            }
                            catch { }
                        }
                        lock (sync)
                        {
                            filePath = Path.Combine(EnvironmentHelper.ApplicationTempDirectory, fileName);
                            if (!File.Exists(filePath))
                            {
                                client.DownloadFile(attachUri, filePath);
                            }
                        }
                    }
                }
                ProcessStartInfo pInfo = new ProcessStartInfo(filePath);
                pInfo.WindowStyle = ProcessWindowStyle.Maximized;
                pInfo.WorkingDirectory = EnvironmentHelper.ApplicationTempDirectory;
                Process p = new Process();
                p.StartInfo = pInfo;
                p.Start();
                AddDocument(filePath);
            }
        }


        private object sync = new object();




        #endregion


        #region Controllo eventuale numero di documenti aperti

        private DispatcherTimer documentsTimer = null;

        /// <summary>
        /// Verifico i documenti aperti
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        public void CheckOpenedDocuments(object sender, EventArgs e)
        {
            List<string> docList = new List<string>();
            Application.Current.Dispatcher.Invoke((ThreadStart)delegate
            {
                docList = OpenedDocuments.ToList();
            });
            foreach (string doc in docList)
            {
                bool toRemove = false;
                if (!File.Exists(doc))
                {
                    toRemove = true;
                }
                else
                {
                    try
                    {
                        for (int i = 0; i < 10; i++)
                        {
                            toRemove = false;
                            using (Stream str = File.Open(doc, FileMode.Open, FileAccess.ReadWrite, FileShare.None))
                            {
                                toRemove = true;
                            }
                            if (!toRemove)
                            {
                                break;
                            }
                            Thread.Sleep(100);
                        }
                    }
                    catch { }
                }
                if (toRemove)
                {
                    RemoveDocument(doc);
                    if (File.Exists(doc))
                    {
                        File.Delete(doc);
                    }
                }
            }
        }

        
        #endregion


        #region Elenco degli allegati aperti


        private List<string> OpenedDocuments = new List<string>();


        private void AddDocument(string document)
        {
            Application.Current.Dispatcher.Invoke((ThreadStart)delegate
            {
                OpenedDocuments.Add(document);
                RaisePropertyChanged(() => Message);
            });
        }


        private void RemoveDocument(string document)
        {
            Application.Current.Dispatcher.Invoke((ThreadStart)delegate
            {
                if (OpenedDocuments.Contains(document))
                {
                    OpenedDocuments.Remove(document);
                    RaisePropertyChanged(() => Message);
                }
            });
        }
        #endregion

    }
}
